package com.ruoyi.system.service.impl;

import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.PageInFoDomain;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.enums.AuditStatusEnums;
import com.ruoyi.system.enums.DoingStatusEnums;
import com.ruoyi.system.enums.RoleEnums;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.INursingRecordService;
import com.ruoyi.system.utils.PageHelperUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;


import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;




/**
 * @author jinyao
 */
@Service
@RequiredArgsConstructor
public class NursingRecordServiceImpl implements INursingRecordService {

    private final NursingRecordMapper nursingRecordMapper;
    private final SysUserMapper sysUserMapper;
    private final SysFeeMapper sysFeeMapper;
    private final SysLeaveMapper sysLeaveMapper;
    private final UserRelationMapper userRelationMapper;
    private final SysMessageMapper sysMessageMapper;
    private final NurseLeaveMapper nurseLeaveMapper;

    @Override
    public PageInFoDomain<NursingRecord> selectNursingRecordList(NursingRecord nursingRecord) {

        List<NursingRecord> nursingRecords = selectList(nursingRecord);
        PageInfo<NursingRecord> pageInfo = new PageInfo<>(nursingRecords);
        PageInFoDomain<NursingRecord> pageInFoDomain = new PageInFoDomain<>();
        // 设置分页信息
        pageInFoDomain.setPageNum(pageInfo.getPageNum());
        pageInFoDomain.setRows(pageInfo.getList());
        pageInFoDomain.setTotal(pageInfo.getTotal());
        return pageInFoDomain;
    }

    private List<NursingRecord> selectList(NursingRecord nursingRecord) {
        Example example = new Example(NursingRecord.class);
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("delFlag", "0");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (!loginUser.getUser().isAdmin()){
            List<SysRole> roles = loginUser.getUser().getRoles();
            //护理员只能看到他自己的护理记录
            if (!roles.isEmpty() && roles.stream().anyMatch(m -> RoleEnums.nurse.getValue().equals(m.getRoleKey()))) {
                criteria.andEqualTo("nurseId", loginUser.getUserId());
            }
            //老人只能看到他自己的记录
            if (!roles.isEmpty() && roles.stream().anyMatch(m -> RoleEnums.elder.getValue().equals(m.getRoleKey()))){
                criteria.andEqualTo("elderUserId", loginUser.getUserId());
            }
            //家属只能看到自己家属的记录
            if (!roles.isEmpty() && roles.stream().anyMatch(m -> RoleEnums.family.getValue().equals(m.getRoleKey()))){
                UserRelation userRelation = new UserRelation();
                userRelation.setFamilyUserId(loginUser.getUserId());
                List<UserRelation> userRelations = userRelationMapper.selectUserRelationList(userRelation);
                if (!userRelations.isEmpty()){
                    Set<Long> collect = userRelations.stream().map(UserRelation::getElderUserId).collect(Collectors.toSet());
                    criteria.andIn("elderUserId", collect);
                }
            }
        }
        PageHelperUtils.startPage(nursingRecord.getPageNum(),nursingRecord.getPageSize());
        return nursingRecordMapper.selectByExample(example);
    }

    @Override
    public NursingRecord selectNursingRecordById(Long id) {
        return nursingRecordMapper.selectByPrimaryKey(id);
    }

    @Override
    public int insertNursingRecord(NursingRecord nursingRecord) {
        Date nursingTime = nursingRecord.getNursingTime();
        NursingRecord record = new NursingRecord();
        record.setAuditStatus("1");
        //查询所有已经审核完成的审核记录
        List<NursingRecord> recordList = selectList(record);
        //选取护理与人员
        //选取规则 1 护理时间不冲突 2 护理人员未请假 3 护理计数器小的
        //1 护理时间不冲突
        //排除护理时间冲突的医护人员
        Set<Long> filterNurseIds = new HashSet<>();
        if (!recordList.isEmpty()) {
            List<NursingRecord> filterNursingRecord = recordList.parallelStream().filter(m -> m.getNursingTime().compareTo(nursingTime) == 0 && StringUtils.isNotBlank(m.getNurseId())).collect(Collectors.toList());
            if (!filterNursingRecord.isEmpty()){
                filterNursingRecord.stream().
                        map(m -> Long.parseLong(m.getNurseId())).forEach(filterNurseIds::add);
            }
        }
        //2 护理人员未请假
        //排除请假的护理人
        NurseLeave nurseLeave = new NurseLeave();
        nurseLeave.setDelFlag("0");
        nurseLeave.setStatus("1");
        List<NurseLeave> nurseLeaves = nurseLeaveMapper.selectNurseLeaveList(nurseLeave);
        if (!nurseLeaves.isEmpty()){
            List<NurseLeave> collect = nurseLeaves.parallelStream().filter(m -> nursingTime.compareTo(m.getStartTime()) >= 0 && nursingTime.compareTo(m.getEndTime()) <= 0).collect(Collectors.toList());
            if (!collect.isEmpty()){
                collect.stream().map(NurseLeave::getNurseId).forEach(filterNurseIds::add);
            }
        }
        //3 护理计数器比较小的
        SysUser sysUser = new SysUser();
        sysUser.setDelFlag("0");
        sysUser.setUserIds(filterNurseIds);
        List<SysUser> sysUsers = sysUserMapper.selectNurseList(sysUser);
        if (sysUsers.isEmpty()){
            throw new RuntimeException("暂时您没有可选的护理员 请查看护理员们的护理时间和请假时间");
        }
        SysUser sysUser1 = sysUsers.stream().sorted(Comparator.comparing(SysUser::getTreatmentsNumber)).findAny().orElseThrow(() -> new RuntimeException("暂时您没有可选的护理员 请查看护理员们的护理时间和请假时间"));
        nursingRecord.setNurseId(String.valueOf(sysUser1.getUserId()));
        nursingRecord.setNurseName(sysUser1.getNickName());

        //遍历
        List<SysLeave> sysLeaves = sysLeaveMapper.selectSysLeaveByElderUserId(nursingRecord.getElderUserId());
        if (!sysLeaves.isEmpty()) {
            List<SysLeave> collect = sysLeaves.parallelStream().filter(m -> "0".equals(m.getDelFlag()) && !"2".equals(m.getStatus())).collect(Collectors.toList());
            AtomicBoolean atomicBoolean = new AtomicBoolean(true);
            if (!collect.isEmpty()) {
                for (SysLeave m : collect) {
                    //护理时间

                    if (nursingTime.compareTo(m.getStartTime()) >= 0 && nursingTime.compareTo(m.getEndTime()) <= 0) {
                        atomicBoolean.set(false);
                        break;
                    }
                }
            }
            if (!atomicBoolean.get()) {
                throw new RuntimeException("护理时间冲突");
            }
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 新建时设置审核状态为未审核
        nursingRecord.setAuditStatus(AuditStatusEnums.TO_BE_REVIEWED.getCode());
        // 设置插入时的一些默认值
        nursingRecord.setDelFlag("0");
        nursingRecord.setCreateBy(loginUser.getUsername());
        nursingRecord.setCreateTime(DateUtils.getNowDate());
        sysUser1.setTreatmentsNumber(sysUser1.getTreatmentsNumber() + 1);
        sysUserMapper.updateUser(sysUser1);
        return nursingRecordMapper.insertSelective(nursingRecord);
    }

    @Override
    public int updateNursingRecord(NursingRecord nursingRecord) {
        // 经过审核的记录不可以修改
        NursingRecord nursingRecordSelectedSql = nursingRecordMapper.selectByPrimaryKey(nursingRecord.getId());
        String auditStatus = nursingRecordSelectedSql.getAuditStatus();
        if (!auditStatus.equals(AuditStatusEnums.TO_BE_REVIEWED.getCode())){
            throw new RuntimeException("不是未审核状态,不支持修改");
        }
        if (DoingStatusEnums.Deactivated.getCode().equals(nursingRecordSelectedSql.getStatus())){
            throw new RuntimeException("停用的不支持修改");
        }
        return nursingRecordMapper.updateByPrimaryKeySelective(nursingRecord);
    }

    @Override
    public int deleteNursingRecordByIds(String ids) {
        if (ids != null && StringUtils.isNotEmpty(ids)){
            throw new RuntimeException("不支持删除");
        }
        return nursingRecordMapper.deleteByPrimaryKey(Convert.toLongArray(ids));
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, DuplicateKeyException.class})
    public Integer audit(NursingRecord nursingRecord) {
        NursingRecord nursingRecordSql = nursingRecordMapper.selectByPrimaryKey(nursingRecord.getId());
        if (!nursingRecordSql.getAuditStatus().equals(AuditStatusEnums.TO_BE_REVIEWED.getCode())){
            throw new RuntimeException("已经审核过的数据不能再次进行审核");
        }
        if (DoingStatusEnums.Deactivated.getCode().equals(nursingRecordSql.getStatus())){
            throw new RuntimeException("停用的不支持审核");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 如果是驳回状态 不需要在用户表里扣除余额
        if (nursingRecord.getAuditStatus().equals(AuditStatusEnums.REFUSE.getCode())){
            //只需要更改审核状态
            nursingRecord.setAuditStatus(AuditStatusEnums.REFUSE.getCode());
        }else {
            // 审核通过 需要在用户表里扣除余额 和 在费用表里处理记录
            Long elderUserId = nursingRecordSql.getElderUserId();
            SysUser sysUser = sysUserMapper.selectUserById(elderUserId);
            if (sysUser.getBalance() == null || sysUser.getBalance().compareTo(nursingRecord.getNursingFee()) < 0){
                throw new RuntimeException("余额不足");
            }
            sysUser.setBalance(sysUser.getBalance().subtract(nursingRecord.getNursingFee()));
            sysUserMapper.updateUser(sysUser);
            SysFee sysFee = getSysFee(nursingRecord, elderUserId, sysUser);
            sysFeeMapper.insertSysFee(sysFee);
            nursingRecord.setAuditStatus(AuditStatusEnums.PASS.getCode());
        }
        nursingRecord.setAuditBy(loginUser.getUsername());
        nursingRecord.setAuditTime(DateUtils.getNowDate());
        return nursingRecordMapper.updateByPrimaryKeySelective(nursingRecord);
    }

    @Override
    public int stop(Long id) {
        NursingRecord nursingRecord = nursingRecordMapper.selectByPrimaryKey(id);
        if (nursingRecord.getStatus().equals(DoingStatusEnums.Deactivated.getCode())){
            throw new RuntimeException("已经停用的不支持再次停用");
        }
        if (nursingRecord.getAuditStatus().equals(AuditStatusEnums.PASS.getCode()) || nursingRecord.getAuditStatus().equals(AuditStatusEnums.REFUSE.getCode())){
            throw new RuntimeException("审核通过和驳回的不支持取消");
        }
        nursingRecord.setStatus(DoingStatusEnums.Deactivated.getCode());
        int i = nursingRecordMapper.updateByPrimaryKeySelective(nursingRecord);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user1 = loginUser.getUser();
        SysMessage elderMessage = new SysMessage();
        elderMessage.setTitle(user1.getNickName() + "取消了护理");
        elderMessage.setContent("尊敬的" + nursingRecord.getNurseName() + "，您的护理已取消，请您知悉。");
        elderMessage.setMessageType("3");
        elderMessage.setReceiverId(Long.parseLong(nursingRecord.getNurseId()));
        elderMessage.setReceiverType("3");
        sysMessageMapper.insertSysMessage(elderMessage);

        return i;
    }

    private  SysFee getSysFee(NursingRecord nursingRecord, Long elderUserId, SysUser sysUser) {
        SysFee sysFee = new SysFee();
        sysFee.setElderUserId(elderUserId);
        sysFee.setElderUserName(sysUser.getNickName());
        sysFee.setFeeType("3");
        //还用取相反数
        sysFee.setAmount(nursingRecord.getNursingFee().negate());
        sysFee.setPaymentStatus("1");
        sysFee.setPaymentMethod("0");
        sysFee.setPaymentTime(DateUtils.getNowDate());
        sysFee.setMonth(DateUtils.parseDateToStr("yyyy-MM", DateUtils.getNowDate()));
        sysFee.setBillNo(DateUtils.dateTimeNow() + RandomStringUtils.randomNumeric(6));
        return sysFee;
    }
}
